//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Mapping Application Block
//===============================================================================

using System;
using System.Diagnostics;
using Microsoft.Practices.EnterpriseLibrary.Common.Instrumentation;
using EntLibContrib.Mapping.Properties;

namespace EntLibContrib.Mapping.Instrumentation
{
	/// <summary>
	/// Provides the concrete instrumentation for the logical events raised by a <see cref="MappingInstrumentationProvider"/> object.
	/// </summary>
	[HasInstallableResources]
	[PerformanceCountersDefinition(MappingCountersCategoryName, "MappingCountersCategoryHelpQuery")]
	[EventLogDefinition("Application", EventLogSourceName)]
	public class MappingInstrumentationListener : InstrumentationListener
	{
		#region Constants
		/// <summary>
		/// The name of the event log source.
		/// </summary>
		public const string EventLogSourceName = "Enterprise Library Mapping";
		/// <summary>
		/// The name of the mapping counters.
		/// </summary>
		public const string MappingCountersCategoryName = "Enterprise Library Mapping Counters";
		/// <summary>
		/// Total Mapping To Domain Object Count
		/// </summary>
		public const string MappingTotalToDomainObjectCountCounterName = "Total Mapping to Domain Object Count";
		/// <summary>
		/// Total Mapping From Domain Object Count
		/// </summary>
		public const string MappingTotalFromDomainObjectCountCounterName = "Total Mapping from Domain Object Count";
		/// <summary>
		/// Basic Mapping To Domain Object Count
		/// </summary>
		public const string MappingBasicToDomainObjectCountCounterName = "Basic Mapping to Domain Object Count";
		/// <summary>
		/// Basic Mapping From Domain Object Count
		/// </summary>
		public const string MappingBasicFromDomainObjectCountCounterName = "Basic Mapping from Domain Object Count";
		/// <summary>
		/// Super Mapping To Domain Object Count
		/// </summary>
		public const string MappingSuperToDomainObjectCountCounterName = "Super Mapping to Domain Object Count";
		/// <summary>
		/// Super Mapping From Domain Object Count
		/// </summary>
		public const string MappingSuperFromDomainObjectCountCounterName = "Super Mapping from Domain Object Count";
		/// <summary>
		/// Custom Mapping To Domain Object Count
		/// </summary>
		public const string MappingCustomToDomainObjectCountCounterName = "Custom Mapping to Domain Object Count";
		/// <summary>
		/// Custom Mapping From Domain Object Count
		/// </summary>
		public const string MappingCustomFromDomainObjectCountCounterName = "Custom Mapping from Domain Object Count";
		/// <summary>
		/// Mapping To Domain Object Rate
		/// </summary>
		public const string MappingToDomainObjectRateCounterName = "Mapping to Domain Object Rate";
		/// <summary>
		/// Mapping From Domain Object Rate
		/// </summary>
		public const string MappingFromDomainObjectRateCounterName = "Mapping from Domain Object Rate";
		/// <summary>
		/// Basic Mapping To Domain Object Rate
		/// </summary>
		public const string MappingBasicToDomainObjectRateCounterName = "Basic Mapping to Domain Object Rate";
		/// <summary>
		/// Basic Mapping From Domain Object Rate
		/// </summary>
		public const string MappingBasicFromDomainObjectRateCounterName = "Basic Mapping from Domain Object Rate";
		/// <summary>
		/// Super Mapping To Domain Object Rate
		/// </summary>
		public const string MappingSuperToDomainObjectRateCounterName = "Super Mapping to Domain Object Rate";
		/// <summary>
		/// Super Mapping From Domain Object Rate
		/// </summary>
		public const string MappingSuperFromDomainObjectRateCounterName = "Super Mapping from Domain Object Rate";
		/// <summary>
		/// Custom Mapping To Domain Object Rate
		/// </summary>
		public const string MappingCustomToDomainObjectRateCounterName = "Custom Mapping to Domain Object Rate";
		/// <summary>
		/// Custom Mapping From Domain Object Rate
		/// </summary>
		public const string MappingCustomFromDomainObjectRateCounterName = "Custom Mapping from Domain Object Rate";
		#endregion

		#region Static Fields
		static EnterpriseLibraryPerformanceCounterFactory factory = new EnterpriseLibraryPerformanceCounterFactory();
		#endregion

		#region Fields
		private string instanceName;
		private IEventLogEntryFormatter eventLogEntryFormatter;
		#endregion

		#region Counters
		[PerformanceCounter(MappingTotalToDomainObjectCountCounterName, "MappingTotalToDomainObjectCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingTotalToDomainObjectCountCounter;

		[PerformanceCounter(MappingTotalFromDomainObjectCountCounterName, "MappingTotalFromDomainObjectCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingTotalFromDomainObjectCountCounter;

		[PerformanceCounter(MappingBasicToDomainObjectCountCounterName, "MappingBasicToDomainObjectCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingBasicToDomainObjectCountCounter;

		[PerformanceCounter(MappingBasicFromDomainObjectCountCounterName, "MappingBasicFromDomainObjectCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingBasicFromDomainObjectCountCounter;

		[PerformanceCounter(MappingSuperToDomainObjectCountCounterName, "MappingSuperToDomainObjectCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingSuperToDomainObjectCountCounter;

		[PerformanceCounter(MappingSuperFromDomainObjectCountCounterName, "MappingSuperFromDomainObjectCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingSuperFromDomainObjectCountCounter;

		[PerformanceCounter(MappingCustomToDomainObjectCountCounterName, "MappingCustomToDomainObjectCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingCustomToDomainObjectCountCounter;

		[PerformanceCounter(MappingCustomFromDomainObjectCountCounterName, "MappingCustomFromDomainObjectCountCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingCustomFromDomainObjectCountCounter;

		[PerformanceCounter(MappingToDomainObjectRateCounterName, "MappingToDomainObjectRateCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingToDomainObjectRateCounter;

		[PerformanceCounter(MappingFromDomainObjectRateCounterName, "MappingFromDomainObjectRateCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingFromDomainObjectRateCounter;

		[PerformanceCounter(MappingBasicToDomainObjectRateCounterName, "MappingBasicToDomainObjectRateCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingBasicToDomainObjectRateCounter;

		[PerformanceCounter(MappingBasicFromDomainObjectRateCounterName, "MappingBasicFromDomainObjectRateCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingBasicFromDomainObjectRateCounter;

		[PerformanceCounter(MappingSuperToDomainObjectRateCounterName, "MappingSuperToDomainObjectRateCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingSuperToDomainObjectRateCounter;

		[PerformanceCounter(MappingSuperFromDomainObjectRateCounterName, "MappingSuperFromDomainObjectRateCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingSuperFromDomainObjectRateCounter;

		[PerformanceCounter(MappingCustomToDomainObjectRateCounterName, "MappingCustomToDomainObjectRateCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingCustomToDomainObjectRateCounter;

		[PerformanceCounter(MappingCustomFromDomainObjectRateCounterName, "MappingCustomFromDomainObjectRateCounterHelpQuery", PerformanceCounterType.NumberOfItems64)]
		EnterpriseLibraryPerformanceCounter mappingCustomFromDomainObjectRateCounter;
		#endregion

		#region Construction
		/// <summary>
		/// Initializes a new instance of the <see cref="MappingInstrumentationListener"/> class.
		/// </summary>
		/// <param name="instanceName">The name of the <see cref="IMapper"/> instance this instrumentation listener is created for.</param>
		/// <param name="performanceCountersEnabled"><b>true</b> if performance counters should be updated.</param>
		/// <param name="eventLoggingEnabled"><b>true</b> if event log entries should be written.</param>
		/// <param name="wmiEnabled"><b>true</b> if WMI events should be fired.</param>
		/// <param name="applicationInstanceName">The application instance name.</param>
		public MappingInstrumentationListener(string instanceName,
																					bool performanceCountersEnabled,
																					bool eventLoggingEnabled,
																					bool wmiEnabled,
																					string applicationInstanceName)
			: this(instanceName, performanceCountersEnabled, eventLoggingEnabled, wmiEnabled, new AppDomainNameFormatter(applicationInstanceName))
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="MappingInstrumentationListener"/> class.
		/// </summary>
		/// <param name="instanceName">The name of the <see cref="IMapper"/> instance this instrumentation listener is created for.</param>
		/// <param name="performanceCountersEnabled"><b>true</b> if performance counters should be updated.</param>
		/// <param name="eventLoggingEnabled"><b>true</b> if event log entries should be written.</param>
		/// <param name="wmiEnabled"><b>true</b> if WMI events should be fired.</param>
		/// <param name="nameFormatter">The <see cref="IPerformanceCounterNameFormatter"/> that is used to create a unique name for each <see cref="PerformanceCounter"/> instance.</param>
		public MappingInstrumentationListener(string instanceName,
																					bool performanceCountersEnabled,
																					bool eventLoggingEnabled,
																					bool wmiEnabled,
																					IPerformanceCounterNameFormatter nameFormatter)
			: base(new string[] { instanceName }, performanceCountersEnabled, eventLoggingEnabled, wmiEnabled, nameFormatter)
		{
			this.instanceName = instanceName;

			if (EventLoggingEnabled)
				this.eventLogEntryFormatter = new EventLogEntryFormatter(InternalResources.MappingBlockName);
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
		/// Handler for the <see cref="MappingInstrumentationProvider.MappingTo"/> event.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">Data for the event.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
		[InstrumentationConsumer("MappingTo")]
		public void MappingTo(object sender, MappingToEventArgs e)
		{
			if (PerformanceCountersEnabled)
			{
				mappingTotalToDomainObjectCountCounter.Increment();
				mappingToDomainObjectRateCounter.Increment();

				switch (e.MapperType)
				{
					case MapperType.Basic:
						mappingBasicToDomainObjectCountCounter.Increment();
						mappingBasicToDomainObjectRateCounter.Increment();
						break;
					case MapperType.Super:
						mappingSuperToDomainObjectCountCounter.Increment();
						mappingSuperToDomainObjectRateCounter.Increment();
						break;
					default:
						mappingCustomToDomainObjectCountCounter.Increment();
						mappingCustomToDomainObjectRateCounter.Increment();
						break;
				}
			}
		}

		/// <summary>
		/// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
		/// Handler for the <see cref="MappingInstrumentationProvider.MappingFrom"/> event.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">Data for the event.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
		[InstrumentationConsumer("MappingFrom")]
		public void MappingFrom(object sender, MappingFromEventArgs e)
		{
			if (PerformanceCountersEnabled)
			{
				mappingTotalFromDomainObjectCountCounter.Increment();
				mappingFromDomainObjectRateCounter.Increment();

				switch (e.MapperType)
				{
					case MapperType.Basic:
						mappingBasicFromDomainObjectCountCounter.Increment();
						mappingBasicFromDomainObjectRateCounter.Increment();
						break;
					case MapperType.Super:
						mappingSuperFromDomainObjectCountCounter.Increment();
						mappingSuperFromDomainObjectRateCounter.Increment();
						break;
					default:
						mappingCustomFromDomainObjectCountCounter.Increment();
						mappingCustomFromDomainObjectRateCounter.Increment();
						break;
				}
			}
		}

		/// <summary>
		/// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
		/// Handler for the <see cref="MappingInstrumentationProvider.MapperFailed"/> event.
		/// </summary>
		/// <param name="sender">Sender of the event.</param>
		/// <param name="e">Data for the event.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
		[InstrumentationConsumer("MapperFailed")]
		public void MapperFailed(object sender, MapperFailureEventArgs e)
		{
			if (e == null)
				throw new ArgumentNullException("e");
				
			if (WmiEnabled)
				FireManagementInstrumentation(new MapperFailureEvent(instanceName, e.ErrorMessage, e.Exception.ToString()));

			if (EventLoggingEnabled)
			{
				string errorMessage = string.Format(InternalResources.Culture, InternalResources.ErrorMapperOperationFailedMessage, instanceName);
				string entryText = eventLogEntryFormatter.GetEntryText(errorMessage, e.Exception, e.ErrorMessage);

				EventLog.WriteEntry(GetEventSourceName(), entryText, EventLogEntryType.Error);
			}
		}
		#endregion

		#region Protected Methods
		/// <summary>
		/// Creates the performance counters to instrument the mapper events for the specified instance names.
		/// </summary>
		/// <param name="instanceNames">The instance names for the performance counters.</param>
		protected override void CreatePerformanceCounters(string[] instanceNames)
		{
			mappingTotalToDomainObjectCountCounter = factory.CreateCounter(MappingCountersCategoryName, MappingTotalToDomainObjectCountCounterName, instanceNames);
			mappingTotalFromDomainObjectCountCounter = factory.CreateCounter(MappingCountersCategoryName, MappingTotalFromDomainObjectCountCounterName, instanceNames);
			mappingBasicToDomainObjectCountCounter = factory.CreateCounter(MappingCountersCategoryName, MappingBasicToDomainObjectCountCounterName, instanceNames);
			mappingBasicFromDomainObjectCountCounter = factory.CreateCounter(MappingCountersCategoryName, MappingBasicFromDomainObjectCountCounterName, instanceNames);
			mappingSuperToDomainObjectCountCounter = factory.CreateCounter(MappingCountersCategoryName, MappingSuperToDomainObjectCountCounterName, instanceNames);
			mappingSuperFromDomainObjectCountCounter = factory.CreateCounter(MappingCountersCategoryName, MappingSuperFromDomainObjectCountCounterName, instanceNames);
			mappingCustomToDomainObjectCountCounter = factory.CreateCounter(MappingCountersCategoryName, MappingCustomToDomainObjectCountCounterName, instanceNames);
			mappingCustomFromDomainObjectCountCounter = factory.CreateCounter(MappingCountersCategoryName, MappingCustomFromDomainObjectCountCounterName, instanceNames);
			mappingToDomainObjectRateCounter = factory.CreateCounter(MappingCountersCategoryName, MappingToDomainObjectRateCounterName, instanceNames);
			mappingFromDomainObjectRateCounter = factory.CreateCounter(MappingCountersCategoryName, MappingFromDomainObjectRateCounterName, instanceNames);
			mappingBasicToDomainObjectRateCounter = factory.CreateCounter(MappingCountersCategoryName, MappingBasicToDomainObjectRateCounterName, instanceNames);
			mappingBasicFromDomainObjectRateCounter = factory.CreateCounter(MappingCountersCategoryName, MappingBasicFromDomainObjectRateCounterName, instanceNames);
			mappingSuperToDomainObjectRateCounter = factory.CreateCounter(MappingCountersCategoryName, MappingSuperToDomainObjectRateCounterName, instanceNames);
			mappingSuperFromDomainObjectRateCounter = factory.CreateCounter(MappingCountersCategoryName, MappingSuperFromDomainObjectRateCounterName, instanceNames);
			mappingCustomToDomainObjectRateCounter = factory.CreateCounter(MappingCountersCategoryName, MappingCustomToDomainObjectRateCounterName, instanceNames);
			mappingCustomFromDomainObjectRateCounter = factory.CreateCounter(MappingCountersCategoryName, MappingCustomFromDomainObjectRateCounterName, instanceNames);
		}
		#endregion
	}
}